//! Definitions for the ROS2 `rcl_interfaces` package.
//!
//! Based on definitions taken from <https://github.com/ros2/rcl_interfaces/tree/rolling/rcl_interfaces/msg>

use serde::{Deserialize, Serialize};

use super::builtin_interfaces::Time;

/// Log levels for ROS2 logging.
///
/// These correspond to the enum in rcutils/logger.h and follow the Python Standard logging levels.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[repr(u8)]
#[serde(from = "u8", into = "u8")]
pub enum LogLevel {
    /// Unknown log level
    Unknown = 0,

    /// Debug is for pedantic information, which is useful when debugging issues
    Debug = 10,

    /// Info is the standard informational level and is used to report expected information
    Info = 20,

    /// Warning is for information that may potentially cause issues or possibly unexpected behavior
    Warn = 30,

    /// Error is for information that this node cannot resolve
    Error = 40,

    /// Information about an impending node shutdown
    Fatal = 50,
}

impl From<u8> for LogLevel {
    fn from(value: u8) -> Self {
        match value {
            10 => Self::Debug,
            20 => Self::Info,
            30 => Self::Warn,
            40 => Self::Error,
            50 => Self::Fatal,
            _ => Self::Unknown,
        }
    }
}

impl From<LogLevel> for u8 {
    fn from(val: LogLevel) -> Self {
        val as Self
    }
}

impl std::fmt::Display for LogLevel {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}",
            match self {
                Self::Debug => "DEBUG",
                Self::Info => "INFO",
                Self::Warn => "WARN",
                Self::Error => "ERROR",
                Self::Fatal => "CRITICAL",
                Self::Unknown => "TRACE",
            }
        )
    }
}

/// This message represents a log entry from a ROS2 node.
///
/// The logging levels follow the Python Standard logging levels:
/// <https://docs.python.org/3/library/logging.html#logging-levels>
///
/// And are implemented in rcutils as well:
/// <https://github.com/ros2/rcutils/blob/35f29850064e0c33a4063cbc947ebbfeada11dba/include/rcutils/logging.h#L164-L172>
///
/// This leaves space for other standard logging levels to be inserted in the middle in the future,
/// as well as custom user defined levels.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Log {
    /// Timestamp when this message was generated by the node
    pub stamp: Time,

    /// Corresponding log level
    pub level: LogLevel,

    /// The name representing the logger this message came from
    pub name: String,

    /// The full log message
    pub msg: String,

    /// The file the message came from
    pub file: String,

    /// The function the message came from
    pub function: String,

    /// The line in the file the message came from
    pub line: u32,
}
